package com.tf8.treasure.utils;


import com.tf8.treasure.enums.ReturnType;
import com.tf8.treasure.exception.RequestException;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DateUtil {

    public static final String YYYYMMDD = "yyyyMMdd";
    public static final String HHMMSS = "HHmmss";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYYMMDDHHMMSSSSSS = "yyyyMMddHHmmssSSSS";
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYY_MM_DDHH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYY_MM_DDTHH_MM_SS_SSS = "yyyy-MM-dd'T'HH:mm:ss:SSS";

    public static String dateToString() {
        return DateTime.now().toString(YYYYMMDDHHMMSS);
    }

    public static String nowToString() {
        return DateTime.now().toString(YYYYMMDDHHMMSS);
    }

    public static String nowToString(String format) {
        return DateTime.now().toString(format);
    }

    public static String nowToString(Date date, String format) {
        return new DateTime(date.getTime()).toString(format);
    }

    public static Date toDate(String strDate, String formatter) {
        try {
            DateTimeFormatter format = DateTimeFormat.forPattern(formatter);
            return DateTime.parse(strDate, format).toDate();
        } catch (Exception e) {
            throw new RequestException(ReturnType.DATE_FORMATE_ERROR);
        }
    }

    /**
     * 增加天,出入日期格式都根据参数决定
     */
    public static String plusDays(String strDate, String inFormatter, Integer days, String outFormatter) {
        DateTimeFormatter format = DateTimeFormat.forPattern(inFormatter);
        return DateTime.parse(strDate, format).plusDays(days).toString(outFormatter);
    }


    /**
     * 减天,出入日期格式都根据参数决定
     */
    public static String minusDays(String strDate, String inFormatter, Integer days, String outFormatter) {
        DateTimeFormatter format = DateTimeFormat.forPattern(inFormatter);
        return DateTime.parse(strDate, format).minusDays(days).toString(outFormatter);
    }


    /**
     * 增加天,出入日期格式都根据参数决定
     */
    public static Date plusDays(Date date, Integer days) {
        return new DateTime(date).plusDays(days).toDate();
    }


    /**
     * 减天,出入日期格式都根据参数决定
     */
    public static Date minusDays(Date date, Integer days) {
        return new DateTime(date).minusDays(days).toDate();
    }


    public static String formateTime(Date date, String formatter) {
        DateTime dt3 = new DateTime(date);// 2010年2月1
        return dt3.toString(formatter);
    }

    public static String formateTime(Timestamp date, String formatter) {
        DateTime dt3 = new DateTime(date);// 2010年2月1
        return dt3.toString(formatter);
    }

    public static Timestamp paresTime(String strDate, String formatter) {
        DateTime dt4 = DateTimeFormat.forPattern(formatter).parseDateTime(strDate);
        Timestamp ts = new Timestamp(dt4.getMillis());
        return ts;
    }

    public static Timestamp getNextDate(int next) {
        DateTime time = new DateTime();
        DateTime nextTime = time.plusDays(next);
        Timestamp ts = new Timestamp(nextTime.getMillis());
        return ts;
    }

    public static Timestamp getNextDate(Timestamp date, int next) {
        DateTime time = new DateTime();
        DateTime nextTime = time.plusDays(next);
        Timestamp ts = new Timestamp(nextTime.getMillis());
        return ts;
    }

    public static Timestamp getNextDate(Date date, int next) {
        DateTime time = new DateTime(date);
        DateTime nextTime = time.plusDays(next);
        Timestamp ts = new Timestamp(nextTime.getMillis());
        return ts;
    }

    public static String getNextDate2(Date date, int next) {
        DateTime time = new DateTime(date);
        DateTime nextTime = time.plusDays(next);
        Timestamp ts = new Timestamp(nextTime.getMillis());
        return formateTime(ts, "yyyy-MM-dd");
    }

    public static Timestamp getNextDateExt(int next) {
        try {
            DateTime time = new DateTime();
            DateTime nextTime = time.plusDays(next);
            Timestamp ts = new Timestamp(nextTime.getMillis());
            String strDate = formateTime(ts, "yyyyMMdd");
            return paresTime(strDate, "yyyyMMdd");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Timestamp getNextDateExt(Timestamp date, int next) {
        try {
            DateTime time = new DateTime(date);
            DateTime nextTime = time.plusDays(next);
            Timestamp ts = new Timestamp(nextTime.getMillis());
            String strDate = formateTime(ts, "yyyyMMdd");
            return paresTime(strDate, "yyyyMMdd");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前时间
     *
     * @return
     * @author: Vinci
     * @time: 2012-5-3 下午03:31:08
     * @modifylog:
     */
    public static Timestamp getCurrTimestamp() {
        return new Timestamp(new Date().getTime());
    }

    public static String getCurrDate(String formate) {
        return formateTime(new Date(), formate);
    }

    public static String getCurrDate() {
        return formateTime(new Date(), "yyyyMMdd");
    }

    /**
     * 当月第一天
     *
     * @return
     */
    public static String getDayOfMonth(int whichDate) {
        Calendar calendar = Calendar.getInstance();
        Date theDate = calendar.getTime();

        GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance();
        gcLast.setTime(theDate);
        gcLast.set(Calendar.DAY_OF_MONTH, whichDate);
        String day_first = formateTime(new Timestamp(gcLast.getTime().getTime()), "yyyyMMddHHmmss");
        StringBuffer str = new StringBuffer().append(day_first).append("000000");
        return str.toString();

    }

    public static Date getFirstTime(Date date) {
        Calendar cale = Calendar.getInstance();
        // 获取前月的第一天
        cale = Calendar.getInstance();
        cale.setTime(date);
        cale.add(Calendar.MONTH, 0);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        cale.set(Calendar.DATE, 1);
        cale.set(Calendar.HOUR_OF_DAY, 0);
        cale.set(Calendar.MINUTE, 0);
        cale.set(Calendar.SECOND, 0);
        return cale.getTime();
    }

    public static Date getLastTime(Date date) {
        Calendar cale = Calendar.getInstance();
        cale = Calendar.getInstance();
        cale.setTime(date);
        cale.add(Calendar.MONTH, 1);
        cale.set(Calendar.DAY_OF_MONTH, 0);
        cale.set(Calendar.HOUR_OF_DAY, 23);
        cale.set(Calendar.MINUTE, 59);
        cale.set(Calendar.SECOND, 59);
        return cale.getTime();
    }


    /**
     * 当月第一天
     *
     * @return
     */
    public static String getDayOfMonth(Date date, int whichDate) {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance();
        gcLast.setTime(date);
        gcLast.set(Calendar.DAY_OF_MONTH, whichDate);
        String day_first = df.format(gcLast.getTime());
        StringBuffer str = new StringBuffer().append(day_first).append("000000");
        return str.toString();

    }

    /**
     * 当月第一天
     *
     * @return
     */
    public static String getDayOfMonth(int whichDate, String format) {
        SimpleDateFormat df = new SimpleDateFormat(format);
        Calendar calendar = Calendar.getInstance();
        Date theDate = calendar.getTime();

        GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance();
        gcLast.setTime(theDate);
        gcLast.set(Calendar.DAY_OF_MONTH, whichDate);
        String day_first = df.format(gcLast.getTime());
        return day_first;

    }

    /**
     * 第一天
     *
     * @return
     */
    public static String getDayOfWeek(int whichDate, String format) {
        SimpleDateFormat df = new SimpleDateFormat(format);
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, 2);
        Date theDate = calendar.getTime();

        GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance();
        gcLast.setTime(theDate);
        gcLast.set(Calendar.DAY_OF_MONTH, whichDate);
        String day_first = df.format(gcLast.getTime());
        return day_first;

    }

    /**
     * 获取SimpleDateFormat
     *
     * @param parttern 日期格式
     * @return SimpleDateFormat对象
     * @throws RuntimeException 异常：非法日期格式
     */
    public static SimpleDateFormat getDateFormat(String parttern) throws RuntimeException {
        return new SimpleDateFormat(parttern);
    }

    /**
     * 获取日期中的某数值。如获取月份
     *
     * @param date     日期
     * @param dateType 日期格式
     * @return 数值
     */
    public static int getInteger(Date date, int dateType) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(dateType);
    }


    /**
     * 增加日期中某类型的某数值。如增加日期
     *
     * @param date     日期
     * @param dateType 类型
     * @param amount   数值
     * @return 计算后日期
     */
    public static Date addInteger(Date date, int dateType, int amount) {
        Date myDate = null;
        if (date != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(dateType, amount);
            myDate = calendar.getTime();
        }
        return myDate;
    }

    /**
     * 获取精确的日期
     *
     * @param timestamps 时间long集合
     * @return 日期
     */
    public static Date getAccurateDate(List<Long> timestamps) {
        Date date = null;
        long timestamp = 0;
        Map<Long, long[]> map = new HashMap<Long, long[]>();
        List<Long> absoluteValues = new ArrayList<Long>();

        if (timestamps != null && timestamps.size() > 0) {
            if (timestamps.size() > 1) {
                for (int i = 0; i < timestamps.size(); i++) {
                    for (int j = i + 1; j < timestamps.size(); j++) {
                        long absoluteValue = Math.abs(timestamps.get(i) - timestamps.get(j));
                        absoluteValues.add(absoluteValue);
                        long[] timestampTmp = {timestamps.get(i), timestamps.get(j)};
                        map.put(absoluteValue, timestampTmp);
                    }
                }

                // 有可能有相等的情况。如2012-11和2012-11-01。时间戳是相等的
                long minAbsoluteValue = -1;
                if (!absoluteValues.isEmpty()) {
                    // 如果timestamps的size为2，这是差值只有一个，因此要给默认值
                    minAbsoluteValue = absoluteValues.get(0);
                }
                for (int i = 0; i < absoluteValues.size(); i++) {
                    for (int j = i + 1; j < absoluteValues.size(); j++) {
                        if (absoluteValues.get(i) > absoluteValues.get(j)) {
                            minAbsoluteValue = absoluteValues.get(j);
                        } else {
                            minAbsoluteValue = absoluteValues.get(i);
                        }
                    }
                }

                if (minAbsoluteValue != -1) {
                    long[] timestampsLastTmp = map.get(minAbsoluteValue);
                    if (absoluteValues.size() > 1) {
                        timestamp = Math.max(timestampsLastTmp[0], timestampsLastTmp[1]);
                    } else if (absoluteValues.size() == 1) {
                        // 当timestamps的size为2，需要与当前时间作为参照
                        long dateOne = timestampsLastTmp[0];
                        long dateTwo = timestampsLastTmp[1];
                        if ((Math.abs(dateOne - dateTwo)) < 100000000000L) {
                            timestamp = Math.max(timestampsLastTmp[0], timestampsLastTmp[1]);
                        } else {
                            long now = new Date().getTime();
                            if (Math.abs(dateOne - now) <= Math.abs(dateTwo - now)) {
                                timestamp = dateOne;
                            } else {
                                timestamp = dateTwo;
                            }
                        }
                    }
                }
            } else {
                timestamp = timestamps.get(0);
            }
        }

        if (timestamp != 0) {
            date = new Date(timestamp);
        }
        return date;
    }


    /**
     * 将日期字符串转化为日期。失败返回null。
     *
     * @param date     日期字符串
     * @param parttern 日期格式
     * @return 日期
     */
    public static Date StringToDate(String date, String parttern) {
        Date myDate = null;
        if (date != null) {
            try {
                myDate = getDateFormat(parttern).parse(date);
            } catch (Exception e) {
            }
        }
        return myDate;
    }


    /**
     * 将日期转化为日期字符串。失败返回null。
     *
     * @param date     日期
     * @param parttern 日期格式
     * @return 日期字符串
     */
    public static String DateToString(Date date, String parttern) {
        String dateString = null;
        if (date != null) {
            try {
                dateString = getDateFormat(parttern).format(date);
            } catch (Exception e) {
            }
        }
        return dateString;
    }

    /**
     * 增加日期的年份。失败返回null。
     *
     * @param date       日期
     * @param yearAmount 增加数量。可为负数
     * @return 增加年份后的日期
     */
    public static Date addYear(Date date, int yearAmount) {
        return addInteger(date, Calendar.YEAR, yearAmount);
    }


    /**
     * 增加日期的月份。失败返回null。
     *
     * @param date       日期
     * @param yearAmount 增加数量。可为负数
     * @return 增加月份后的日期
     */
    public static Date addMonth(Date date, int yearAmount) {
        return addInteger(date, Calendar.MONTH, yearAmount);
    }


    /**
     * 增加日期的天数。失败返回null。
     *
     * @param date      日期
     * @param dayAmount 增加数量。可为负数
     * @return 增加天数后的日期
     */
    public static Date addDay(Date date, int dayAmount) {
        return addInteger(date, Calendar.DATE, dayAmount);
    }


    /**
     * 增加日期的小时。失败返回null。
     *
     * @param date 日期
     * @return 增加小时后的日期
     */
    public static Date addHour(Date date, int hourAmount) {
        return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount);
    }

    /**
     * 增加日期的分钟。失败返回null。
     *
     * @param date 日期
     * @return 增加分钟后的日期
     */
    public static Date addMinute(Date date, int hourAmount) {
        return addInteger(date, Calendar.MINUTE, hourAmount);
    }


    /**
     * 增加日期的秒钟。失败返回null。
     *
     * @param date      日期
     * @return 增加秒钟后的日期
     */
    public static Date addSecond(Date date, int hourAmount) {
        return addInteger(date, Calendar.SECOND, hourAmount);
    }


    /**
     * 获取日期的年份。失败返回0。
     *
     * @param date 日期
     * @return 年份
     */
    public static int getYear(Date date) {
        return getInteger(date, Calendar.YEAR);
    }

    /**
     * 获取日期的月份。失败返回0。
     *
     * @param date 日期
     * @return 月份
     */
    public static int getMonth(Date date) {
        return getInteger(date, Calendar.MONTH);
    }


    /**
     * 获取日期的天数。失败返回0。
     *
     * @param date 日期
     * @return 天
     */
    public static int getDay(Date date) {
        return getInteger(date, Calendar.DATE);
    }


    /**
     * 获取日期的小时。失败返回0。
     *
     * @param date 日期
     * @return 小时
     */
    public static int getHour(Date date) {
        return getInteger(date, Calendar.HOUR_OF_DAY);
    }


    /**
     * 获取日期的分钟。失败返回0。
     *
     * @param date 日期
     * @return 分钟
     */
    public static int getMinute(Date date) {
        return getInteger(date, Calendar.MINUTE);
    }


    /**
     * 获取日期的秒钟。失败返回0。
     *
     * @param date 日期
     * @return 秒钟
     */
    public static int getSecond(Date date) {
        return getInteger(date, Calendar.SECOND);
    }


    /**
     * 获取日期。
     *
     * @param date 日期
     * @return 日期
     */
    public static String getDate(Date date, String dateFormat) {
        return DateToString(date, dateFormat);
    }


    /**
     * @return 相差天数
     */
    public static int getIntervalDays(Date begin, Date end) {
        DateTime beginDate = new DateTime(getFatalism(begin));
        DateTime endDate = new DateTime(getFatalism(end));
        return Days.daysBetween(beginDate, endDate).getDays();
    }

    public static Date getFatalism(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    public static int getIntervalDays(Timestamp end, Timestamp begin) {
        // date = DateUtils.StringToDate(DateUtils.getDate(date));
        long time = Math.abs(end.getTime() - begin.getTime());
        return (int) time / (24 * 60 * 60 * 1000);
    }

    public static String getLastDate(int days) {
        return DateTime.now().plusDays(days).toString(YYYYMMDD);
    }


}
